package amd64

import (
	"fmt"
	"sync"
	"sync/atomic"

	"gitee.com/u-language/u-language/ucom/internal/utils"
)

const (
	allocX86Reg = 12
	allocSSEReg = 8
)

type virtualRegMem struct {
	_zero int16
	Type  vrmTypeEnum
	Size  VrmSizeEnum
	Num   int32
}

// newvrm创建虚拟寄存器
func newvrm(Type vrmTypeEnum, Size VrmSizeEnum, Num int32) RegEnum {
	return vrmToRegEnum(vrm{Type: Type, Size: Size, Num: Num})
}

func (v vrm) String() string {
	return fmt.Sprintf("Type:=%s Size:=%s _zero:=%d Num:=%d", v.Type.String(), v.Size.String(), v._zero, v.Num)
}

// vrm是虚拟寄存器内存布局
type vrm = virtualRegMem

type virtualReg struct {
	x86num int32
	ssenum int32
}

// VReg是虚拟寄存器分配器
type VReg = virtualReg

// NewVReg创建虚拟寄存器分配器
func NewVReg() *VReg {
	return &VReg{x86num: 0, ssenum: 0}
}

// GetX86Reg获取一个X86的虚拟寄存器
// - bit是寄存器大小
func (v *VReg) GetX86Reg(bit VrmSizeEnum) RegEnum {
	n := atomic.AddInt32(&v.x86num, 1)
	return newvrm(vrmx86, bit, n)
}

// GetSSEReg获取一个SSE的虚拟寄存器
func (v *VReg) GetSSEReg() RegEnum {
	n := atomic.AddInt32(&v.ssenum, 1)
	return newvrm(vrmsse, 0, n)
}

// AllocReg为虚拟寄存器分配实际寄存器
func AllocReg(nodes [][]TextNode, regrun *RegRun, sserun *SseRegRun, vtr *vRegToReg, vt vregToRegTable, Thread bool) {
	nl := len(nodes)
	if nl == 0 {
		return
	}
	var (
		wg                           = utils.NewWaitGroup(Thread)
		_regrun                      = regrun
		_sserun                      = sserun
		vreg_to_reg       *vRegToReg = vtr
		vreg_To_Reg_Table            = vt
	)
	for i := 0; i < nl; i++ {
		for j := 0; j < len(nodes[i]); j++ {
			n := &(nodes[i][j])
			wg.Add()
			bol := isManyKind(*n)
			if bol {
				var info VRegUseInfo = (*n).GetVRegUseInfo()
				x86ret, sseret := vreg_to_reg.Add(info)
				vreg_To_Reg_Table, _regrun, _sserun = vreg_To_Reg_Table.AllOrStore(x86ret, sseret, _regrun, _sserun, Thread)
			}
			go func(n *TextNode, vt vregToRegTable, vtr *vRegToReg, gregrun *RegRun, gsserun *SseRegRun) {
				defer wg.Done()
				switch (*n).Type() {
				case ASSIGN:
					an := (*n).(AssignKind)
					AllocReg([][]TextNode{an.nodes}, gregrun, gsserun, vtr, vt, Thread)
				case StackVarMov:
					sn := (*n).(StackVarMovKind)
					AllocReg([][]TextNode{sn.nodes}, gregrun, gsserun, vtr, vt, Thread)
				case Func:
					fn := (*n).(FuncKind)
					AllocReg(fn.nodes, gregrun, gsserun, vtr, vt, Thread)
				case AmExpr:
					an := (*n).(AmExprKind)
					AllocReg([][]TextNode{an.nodes}, gregrun, gsserun, vtr, vt, Thread)
				case VarMov:
					sn := (*n).(VarMovKind)
					AllocReg([][]TextNode{sn.nodes}, gregrun, gsserun, vtr, vt, Thread)
				case TypeSrcMemDestReg:
					sn := (*n).(*SrcMemDestReg)
					sn.Reg = _RegRePlace(sn.Reg, gregrun, gsserun, vt)
				case TypeSrcRegDestMem:
					sn := (*n).(*SrcRegDestMem)
					sn.Reg = _RegRePlace(sn.Reg, gregrun, gsserun, vt)
				case TypeSrcNumDestReg:
					sn := (*n).(*SrcNumDestReg)
					sn.Reg = _RegRePlace(sn.Reg, gregrun, gsserun, vt)
				case TypeSrcRegDestReg:
					sn := (*n).(*SrcRegDestReg)
					sn.Src = _RegRePlace(sn.Src, gregrun, gsserun, vt)
					sn.Dest = _RegRePlace(sn.Dest, gregrun, gsserun, vt)
				case TypeSrcRegOffsetDestReg:
					sn := (*n).(*SrcRegOffsetDestReg)
					sn.Src = _RegRePlace(sn.Src, gregrun, gsserun, vt)
					sn.Dest = _RegRePlace(sn.Dest, gregrun, gsserun, vt)
				case TypeSrcRegDestRegOffset:
					sn := (*n).(*SrcRegDestRegOffset)
					sn.Src = _RegRePlace(sn.Src, gregrun, gsserun, vt)
					sn.Dest = _RegRePlace(sn.Dest, gregrun, gsserun, vt)
				case TypeSrcNumDestRegOffset:
					sn := (*n).(*SrcNumDestRegOffset)
					sn.Dest = _RegRePlace(sn.Dest, gregrun, gsserun, vt)
				case TypeSrcRegMemDestReg:
					sn := (*n).(*SrcRegMemDestReg)
					sn.Src = _RegRePlace(sn.Src, gregrun, gsserun, vt)
					sn.Dest = _RegRePlace(sn.Dest, gregrun, gsserun, vt)
				case TypeSrcNumDestMem, Labels, StackAlloc, StackFree:
				default:
					panic(fmt.Errorf("未知的类型：%+v", *n))
				}
			}(n, vreg_To_Reg_Table, vtr.Copy(), _regrun, _sserun)
		}
	}
	wg.Wait()
	wg.Close()
}

// _RegRePlace为虚拟寄存器分配实际寄存器
// 同一个虚拟寄存器(x)在vt相同时返回同一个实际寄存器(y)
// 可以认为 vt相同  x ->(推导出) y
func _RegRePlace(reg RegEnum, regrun *RegRun, sserun *SseRegRun, vt vregToRegTable) RegEnum {
	v := _RegEnumTovrm(reg)
	switch v.Type {
	case vrmx86:
		switch v.Size {
		case vrm64bit:
			return vt.GetX86Reg(v, 64, regrun)
		case vrm32bit:
			return vt.GetX86Reg(v, 32, regrun)
		case vrm16bit:
			return vt.GetX86Reg(v, 16, regrun)
		case vrm8bit:
			return vt.GetX86Reg(v, 8, regrun)
		default:
			panic(fmt.Errorf("未知的x86寄存器大小 %+v", v))
		}
	case vrmsse:
		return vt.GetSSEReg(v, sserun)
	default:
		return reg
	}
}

// retVRegUseInfo返回 虚拟寄存器使用信息
// 用于只有一条汇编指令的指令节点
func retVRegUseInfo(reg ...RegEnum) VRegUseInfo {
	regl := len(reg)
	if regl == 0 {
		return VRegUseInfo{}
	}
	var ret VRegUseInfo
	var ret_table = newvregUseTable()
	for i := 0; i < regl; i++ {
		v := _RegEnumTovrm(reg[i])
		if v._zero != 0 { //不是虚拟寄存器
			continue
		}
		if ok := ret_table.VrmOk(v); ok { //同一个虚拟寄存器不重复计算
			continue
		}
		ret_table.Vrm(v)
		switch v.Type {
		case vrmx86:
			ret.X86++
		case vrmsse:
			ret.SSE++
		default: //不是虚拟寄存器
			continue
		}
	}
	return ret
}

// retTextNodeVRegUseInfo返回 虚拟寄存器使用信息
// 用于有多条汇编指令的（组合指令节点）
// 同一个虚拟寄存器 只记录 一次
func retTextNodeVRegUseInfo(nodes []TextNode, ret_table vregUseTable) VRegUseInfo {
	regl := len(nodes)
	if regl == 0 { //没有节点
		return VRegUseInfo{}
	}
	var ret VRegUseInfo
	for i := 0; i < regl; i++ {
		switch n := nodes[i]; n.Type() {
		case ASSIGN:
			an := n.(AssignKind)
			ret = ret.Add(an.GetVRegUseInfo())
		case StackVarMov:
			sn := n.(StackVarMovKind)
			ret = ret.Add(sn.GetVRegUseInfo())
		case AmExpr:
			an := n.(AmExprKind)
			ret = ret.Add(retTextNodeVRegUseInfo(an.nodes, ret_table))
		case VarMov:
			sn := n.(VarMovKind)
			ret = ret.Add(sn.GetVRegUseInfo())
		case TypeSrcMemDestReg:
			sn := n.(*SrcMemDestReg)
			if ok := ret_table.RegEnumOk(sn.Reg); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Reg)
			ret = ret.add(sn.Reg)
		case TypeSrcRegDestMem:
			sn := n.(*SrcRegDestMem)
			if ok := ret_table.RegEnumOk(sn.Reg); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Reg)
			ret = ret.add(sn.Reg)
		case TypeSrcNumDestReg:
			sn := n.(*SrcNumDestReg)
			if ok := ret_table.RegEnumOk(sn.Reg); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Reg)
			ret = ret.add(sn.Reg)
		case TypeSrcRegDestReg:
			sn := n.(*SrcRegDestReg)
			if ok := ret_table.RegEnumOk(sn.Src); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Src)
			ret = ret.add(sn.Src)
			if ok := ret_table.RegEnumOk(sn.Dest); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Dest)
			ret = ret.add(sn.Dest)
		case TypeSrcRegOffsetDestReg:
			sn := n.(*SrcRegOffsetDestReg)
			if ok := ret_table.RegEnumOk(sn.Src); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Src)
			ret = ret.add(sn.Src)
			if ok := ret_table.RegEnumOk(sn.Dest); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Dest)
			ret = ret.add(sn.Dest)
		case TypeSrcRegDestRegOffset:
			sn := n.(*SrcRegDestRegOffset)
			if ok := ret_table.RegEnumOk(sn.Src); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Src)
			ret = ret.add(sn.Src)
			if ok := ret_table.RegEnumOk(sn.Dest); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Dest)
			ret = ret.add(sn.Dest)
		case TypeSrcNumDestRegOffset:
			sn := n.(*SrcNumDestRegOffset)
			if ok := ret_table.RegEnumOk(sn.Dest); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Dest)
			ret = ret.add(sn.Dest)
		case TypeSrcRegMemDestReg:
			sn := n.(*SrcRegMemDestReg)
			if ok := ret_table.RegEnumOk(sn.Src); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Src)
			ret = ret.add(sn.Src)
			if ok := ret_table.RegEnumOk(sn.Dest); ok { //同一个虚拟寄存器不重复计算
				continue
			}
			ret_table.RegEnum(sn.Dest)
			ret = ret.add(sn.Dest)
		case TypeSrcNumDestMem:
		default:
			panic(fmt.Errorf("未知的类型 %+v", n))
		}
	}
	return ret
}

// vRegToReg是 记录 虚拟寄存器分配到实际寄存器 分配数量
type vRegToReg struct {
	x86 int16
	sse int16
}

func _NewvRegToReg() *vRegToReg {
	return &vRegToReg{}
}

// Add记录新增分配数量
func (v *vRegToReg) Add(info VRegUseInfo) (x86ret bool, sseret bool) {
	v.x86 += info.X86
	v.sse += info.SSE
	if v.x86 >= allocX86Reg {
		x86ret = true
		v.x86 = 0
	}
	if v.sse >= allocSSEReg {
		sseret = true
		v.sse = 0
	}
	return
}

// 复制一个副本
func (v *vRegToReg) Copy() *vRegToReg {
	return &vRegToReg{x86: v.x86, sse: v.sse}
}

// vregToRegTable 是虚拟寄存器分配表
type vregToRegTable struct {
	x86map  map[vrm]RegEnum
	x86lock *sync.Mutex
	ssemap  map[vrm]RegEnum
	sselock *sync.Mutex
}

func _NewvregToRegTable() vregToRegTable {
	var ret vregToRegTable
	ret.x86map = make(map[vrm]RegEnum, 3)
	ret.ssemap = make(map[vrm]RegEnum, 3)
	ret.x86lock = new(sync.Mutex)
	ret.sselock = new(sync.Mutex)
	return ret
}

// 获取一个X86虚拟寄存器
// 同一个虚拟寄存器(vrm) 返回同一个实际寄存器(y)
//
//	vrm ->(推导出) y
func (v vregToRegTable) GetX86Reg(vreg vrm, size int8, regrun *RegRun) RegEnum {
	v.x86lock.Lock()
	defer v.x86lock.Unlock()
	if ret, ok := v.x86map[vreg]; ok {
		return ret
	}
	ret := regrun.RetReg(size)
	v.x86map[vreg] = ret
	return ret
}

// 获取一个SSE虚拟寄存器
// 同一个虚拟寄存器(vrm) 返回同一个实际寄存器(y)
//
//	vrm ->(推导出) y
func (v vregToRegTable) GetSSEReg(vreg vrm, sserun *SseRegRun) RegEnum {
	v.sselock.Lock()
	defer v.sselock.Unlock()
	if ret, ok := v.ssemap[vreg]; ok {
		return ret
	}
	ret := sserun.RetReg()
	v.ssemap[vreg] = ret
	return ret
}

// AllOrStore判断 所有可分配寄存器 是否，全部被分配且全部可重新分配
// 所有可分配寄存器（ax bx cx dx r8-r15)
// 全部被分配 == 全部被分配给虚拟寄存器过
// 全部可重新分配 == 全部被分配给虚拟寄存器，且这些虚拟寄存器都不再使用
func (v vregToRegTable) AllOrStore(x86, sse bool, regrun *RegRun, sserun *SseRegRun, Thread bool) (vregToRegTable, *RegRun, *SseRegRun) {
	ret := v
	retreg := regrun
	retsse := sserun
	if x86 {
		ret.x86map = make(map[vrm]RegEnum, 3)
		ret.x86lock = new(sync.Mutex)
		retreg = NewRegRun(Thread)
	}
	if sse {
		ret.ssemap = make(map[vrm]RegEnum, 3)
		ret.sselock = new(sync.Mutex)
		retsse = NewSseRegRun(Thread)
	}
	return ret, retreg, retsse
}

// vregUseTable 是虚拟寄存器使用记录表
type vregUseTable struct {
	ret_table map[vrm]struct{}
}

func newvregUseTable() vregUseTable {
	return vregUseTable{ret_table: make(map[vrm]struct{})}
}

// Vrm记录v
func (table vregUseTable) Vrm(v vrm) {
	table.ret_table[v] = struct{}{}
}

// Vrm返回v是否被记录过
func (table vregUseTable) VrmOk(v vrm) bool {
	_, ok := table.ret_table[v]
	return ok
}

func (table vregUseTable) RegEnumOk(reg RegEnum) bool {
	return table.VrmOk(_RegEnumTovrm(reg))
}

func (table vregUseTable) RegEnum(reg RegEnum) {
	table.Vrm(_RegEnumTovrm(reg))
}
